package com.se.nju.rtvps.network;

import java.io.File;
import java.net.URI;
import java.text.MessageFormat;

import net.jxta.discovery.DiscoveryService;
import net.jxta.document.AdvertisementFactory;
import net.jxta.document.MimeMediaType;
import net.jxta.document.XMLElement;
import net.jxta.exception.PeerGroupException;
import net.jxta.id.IDFactory;
import net.jxta.impl.peergroup.StdPeerGroupParamAdv;
import net.jxta.peer.PeerID;
import net.jxta.peergroup.PeerGroup;
import net.jxta.peergroup.PeerGroupID;
import net.jxta.pipe.PipeID;
import net.jxta.platform.ModuleClassID;
import net.jxta.platform.ModuleSpecID;
import net.jxta.platform.NetworkManager;
import net.jxta.protocol.ModuleClassAdvertisement;
import net.jxta.protocol.ModuleImplAdvertisement;
import net.jxta.protocol.ModuleSpecAdvertisement;
import net.jxta.protocol.PeerGroupAdvertisement;
import net.jxta.protocol.PipeAdvertisement;

import com.se.nju.rtvps.main.ServiceConstants;
import com.se.nju.rtvps.main.StartUp;
import com.se.nju.rtvps.service.*;

public class RTVPSPeerGroup {
	public final static PeerGroupID CUSTOM_PEERGROUP_ID = PeerGroupID.create(URI.create("urn:jxta:uuid-425A5C703CD5454F9C03938A0D65BD5002")); 
	private final static ModuleSpecID CUSTOM_PEERGROUP_MSID = ModuleSpecID.create(URI.create("urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE00000001ACEFC090A5D74844A9DEF43F3003D35A06"));
	private NetworkManager manager;
	private PeerID peerId;
	private PeerGroup npg;
	private PeerGroup rtvps_group;
	private DiscoveryService discoveryService;
	
	public RTVPSPeerGroup() throws Exception{
		peerId = IDFactory.newPeerID(CUSTOM_PEERGROUP_ID);
		manager = new NetworkManager(NetworkManager.ConfigMode.RENDEZVOUS, ServiceConstants.PEER_GROUP_NAME, new File(new File(".cache"), "RTVPSPeerGroup").toURI());
	}
	public void start()throws Exception{
		initGroupService();
		rtvps_group.startApp(new String[0]);
        System.out.println("Started Custom Peer Group : " + rtvps_group);
	}
	
	public void stop()throws Exception{
		System.out.println("Stopping Custom Peer Group : " + rtvps_group);
        rtvps_group.stopApp();
        
        System.out.println("Stopping JXTA");
        manager.stopNetwork();
	}
	
	public void initGroupService()throws Exception{
        manager.setPeerID(this.peerId);
        System.out.println("Starting JXTA");
        npg = manager.startNetwork();
        discoveryService = npg.getDiscoveryService();
        //npg.getRendezVousService().startRendezVous();
        boolean connected = manager.waitForRendezvousConnection(12000);
        System.out.println(MessageFormat.format("Connected :{0}", connected));
        System.out.println("JXTA Started : " + npg);
        
        
        ModuleImplAdvertisement customGroupImplAdv = npg.getAllPurposePeerGroupImplAdvertisement();
        
        // It's custom so we have to change the module spec ID.
        customGroupImplAdv.setModuleSpecID(CUSTOM_PEERGROUP_MSID);

        // StdPeerGroup uses the ModuleImplAdvertisement param section to describe what services to run.
        StdPeerGroupParamAdv customGroupParamAdv = new StdPeerGroupParamAdv(customGroupImplAdv.getParam());

        // Add our Gossip Service to the group
       // customGroupParamAdv.addService(CYRUS_SERVICE_MCID, CYRUS_SERVICE_MSID);
        addService(ControlService.class.getName(),customGroupParamAdv, customGroupImplAdv);
        addService(AskForAliveService.class.getName(),customGroupParamAdv, customGroupImplAdv);
        addService(TransferManagementService.class.getName(),customGroupParamAdv, customGroupImplAdv);

        // update the customGroupImplAdv by updating its param
        customGroupImplAdv.setParam((XMLElement) customGroupParamAdv.getDocument(MimeMediaType.XMLUTF8));

        // publish the ModuleImplAdvertisement for our custom peer group.
        //System.out.println("Custom Group Impl Adv:\n"+customGroupImplAdv);
        discoveryService.publish(customGroupImplAdv);
        discoveryService.remotePublish(customGroupImplAdv);

        // Crete a new PeerGroupAdvertisement instance.
        PeerGroupAdvertisement customGroupAdv = (PeerGroupAdvertisement) AdvertisementFactory.newAdvertisement(PeerGroupAdvertisement.getAdvertisementType());
        
        // Set our chosen peer group ID.
        customGroupAdv.setPeerGroupID(CUSTOM_PEERGROUP_ID);
        
        // Set the peer group name.
        customGroupAdv.setName("Custom RTVPS Peer Group");
        
        // The custom group uses our custom Module Specification.
        customGroupAdv.setModuleSpecID(customGroupImplAdv.getModuleSpecID());
        
       // System.out.println("Custom Group Adv :\n"+customGroupAdv);
        discoveryService.publish(customGroupAdv);
        discoveryService.remotePublish(customGroupAdv);

        // Now we can instantiate the peer group.
        rtvps_group = npg.newGroup(customGroupAdv);
    }
	public void addService(String codat,StdPeerGroupParamAdv pgParamAdv, ModuleImplAdvertisement  implAdv) throws Exception{
		ModuleClassID mcid = IDFactory.newModuleClassID();
		ModuleSpecID msid = IDFactory.newModuleSpecID(mcid);
		pgParamAdv.addService(mcid, msid);
		 // Create a new ModuleImplAdvertisement instance.
        ModuleImplAdvertisement moduleImplAdv = (ModuleImplAdvertisement) AdvertisementFactory.newAdvertisement(ModuleImplAdvertisement.getAdvertisementType());
        
        // Our implementation implements the given ModuleSpecID.
        moduleImplAdv.setModuleSpecID(msid);
        
        // copy compatibility statement from the peer group impl advertisement.
        moduleImplAdv.setCompat(implAdv.getCompat());
        
        moduleImplAdv.setUri("http://jxta-jxse.dev.java.net/download/jxta.jar");
        
        moduleImplAdv.setCode(codat);
        
        moduleImplAdv.setProvider("RTVPS Team");       
        
        moduleImplAdv.setDescription("custom service");

        // publish the service module implementation advertisement.
        //System.out.println("Module Impl Adv:\n"+moduleImplAdv);
        discoveryService.publish(moduleImplAdv);
        discoveryService.remotePublish(moduleImplAdv);
	}
	
	
	
	public DiscoveryService getDiscoveryService(){
		return npg.getDiscoveryService();
	}
	public PeerGroup getNetPeerGroup(){
		return npg;
	}
}
